package com.ipan.kits.timer;

import java.util.Timer;
import java.util.TimerTask;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * 默认计划任务实现类；
 * 1 支持自定义时间段验证；
 * 2 支持任务自定义；
 * 3 支持在给定时间段只执行一次；属性looped为false时，以单次执行；
 * 4 支持在给定时间段执行多次；属性looped为true时，以循环方式执行；
 * 5 特殊功能可以继承该类，自行扩展；
 * 
 * @author iPan
 * @version 2013-07-16
 */
public class TaskImpl extends TimerTask implements Task {
	
	public static final int DEFAULT_PERIOD = 60 * 1000;
	
	/** 定时器 */
	protected Timer timer = null;
	/** 时间段验证器 */
	protected TaskValidateable taskValidater;
	/** 任务执行器 */
	protected TaskRunnable runnable;
	/** 任务名称 */
	protected String name = null;
	/** 任务是否是循环执行；true 循环执行，false只执行一次  */
	protected boolean looped = false;
	/** 任务是否只做一次，使用锁； true 锁上，false 开锁 */
	protected boolean locked = false;
	/** 延迟时间 */
	protected long period = 0L;
	
	/** 是否启动；true 启动，false 关闭 */
	protected volatile boolean on = false;
	/** 是否中断；true 中断，false 未中断 */
	protected volatile boolean intercepted = false;
	/** 是否运行中；true 运行中，false 非运行中 */
	protected volatile boolean running = false;
	
	protected Logger logger = LoggerFactory.getLogger(this.getClass());
	
	public TaskImpl(TaskRunnable runnable) {
		this(runnable, new DefaultValidater(), Thread.currentThread().getClass().getSimpleName() + "-Timer", false, false);
	}
	
	public TaskImpl(TaskRunnable runnable, TaskValidateable taskValidater) {
		this(runnable, taskValidater, Thread.currentThread().getClass().getSimpleName() + "-Timer", false, false);
	}
	
	public TaskImpl(TaskRunnable runnable, TaskValidateable taskValidater, long period) {
		this(runnable, taskValidater, Thread.currentThread().getClass().getSimpleName() + "-Timer", false, period, false);
	}
	
	public TaskImpl(TaskRunnable runnable, TaskValidateable taskValidater, long period, boolean isLoop) {
		this(runnable, taskValidater, Thread.currentThread().getClass().getSimpleName() + "-Timer", isLoop, period, false);
	}
	
	public TaskImpl(TaskRunnable runnable, TaskValidateable taskValidater, String name, boolean isLoop, boolean isDaemon) {
		this(runnable, taskValidater, name, isLoop, DEFAULT_PERIOD, isDaemon);
	}
	
	public TaskImpl(TaskRunnable runnable, TaskValidateable taskValidater, String name, boolean isLoop, long period, boolean isDaemon) {
		this.runnable = runnable;
		this.taskValidater = taskValidater;
		this.name = name;
		this.looped = isLoop;
		this.period = period;
		this.timer = new Timer(name, isDaemon);
	}
	
	/**
	 * 启动；
	 */
	public synchronized void start() {
		if (!this.on) {
			logger.debug("call start thread:{}", Thread.currentThread().getName());
			timer.schedule(this, period, period);
			resetState();
			this.on = true;
			logger.info("定时器[{}]开启 ...", name);
		}
	}
	
	/**
	 * 中断；
	 */
	public synchronized void pause() {
		logger.debug("call intercept thread:{}", Thread.currentThread().getName());
		this.intercepted = true;
		logger.info("定时器[{}]暂停 ...", name);
	}
	
	/**
	 * 恢复；
	 */
	public synchronized void recovery() {
		if (!this.on) {
			throw new RuntimeException("任务未启动，无法恢复！");
		}
		logger.debug("call recovery thread:{}", Thread.currentThread().getName());
		resetState();
		logger.info("定时器[{}]恢复 ...", name);
	}

	/**
	 * 关闭；
	 */
	public synchronized void stop() {
		if (this.on) {
			logger.debug("call stop thread:{}", Thread.currentThread().getName());
			this.intercepted = true;
			this.on = false;
			timer.cancel();
			logger.info("定时器[{}]关闭 ...", name);
		}
	}

	public void run() {
		logger.debug("call run thread:{}", Thread.currentThread().getName());
		if (this.intercepted) {
			return ;
		}
		synchronized(this) {
			this.running = true;
			boolean valied = taskValidater.validate();
			if (looped) {
				execLoopRun(valied);
			} else {
				execRun(valied);
			}
		}
		this.running = false;
	}
	
	// 在给定时间段内，只执行一次；
	// 如果一天内有多个执行时间段，那么每个时间段内都会执行一次；如果不希望这样，请重写该方法！
	protected void execRun(boolean valied) {
		// 在指定时间段内
		// 注意：当天，在该时间段内，如果容器重启，则会出现多次执行的情况；
		if (valied) {
			if (!locked) {
				logger.debug("定时器[{}]执行 ...", name);
				runnable.doRun();
				// 上锁
				locked = true;
				logger.info("定时器[{}]上锁 ...", name);
			}
		} else {
			if (locked) {
				// 开锁
				locked = false;
				logger.info("定时器[{}]开锁 ...", name);
			}
		}
	}
	
	// 验证通过后，只要timer延迟时间到了，就会执行；
	protected void execLoopRun(boolean valied) {
		if (valied) {
			logger.debug("定时器[{}]执行 ...", name);
			runnable.doRun();
		}
	}
	
	// 状态复位
	protected void resetState() {
		this.locked = false;
		this.intercepted = false;
	}
	
	/**
	 * 获取名称；
	 */
	public String getName() {
		return name;
	}

	/**
	 * 是否启动；
	 */
	public boolean isStart() {
		return this.on;
	}
	
	/**
	 * 是否支持循环执行；
	 */
	public boolean isLoop() {
		return this.looped;
	}
	
	/**
	 * 是否中断；
	 */
	public boolean isIntercept() {
		return this.intercepted;
	}
	
	/**
	 * 验证是否通过；
	 */
	public boolean isValid() {
		return taskValidater.validate();
	}
	
	/**
	 * 测试下是否中断，若中断就抛出异常；
	 */
	public void checkIntercept() throws TaskInterceptException {
		logger.debug("call checkIntercept thread:{}", Thread.currentThread().getName());
		if (this.intercepted) {
			throw new TaskInterceptException("系统需要中断！");
		}
	}

	@Override
	public boolean isRunning() {
		return this.running;
	}

	@Override
	public TaskValidateable getValidater() {
		return this.taskValidater;
	}
}
